/*
 *  $Id: upload.cpp,v 1.7 2003/07/13 14:22:57 sbooth Exp $
 *
 *  Copyright (C) 1996 - 2003 Stephen F. Booth
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*! \file upload.cpp
 * \brief File upload demo
 *
 * Tests and demonstrates how to handle uploaded files using the 
 * GNU %cgicc library.
 */

#include <new>
#include <string>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <cstdlib>
#include <complex>
#include "cgicc/CgiDefs.h"
#include "cgicc/Cgicc.h"
#include "cgicc/HTTPHTMLHeader.h"
#include "cgicc/HTMLClasses.h"
#include "CImg.h"
#include "polynomial.h"

#if HAVE_UNAME
#  include <sys/utsname.h>
#endif

#if HAVE_SYS_TIME_H
#  include <sys/time.h>
#endif

// To use logging, the variable gLogFile MUST be defined, and it _must_
// be an ofstream
#if DEBUG
  std::ofstream gLogFile( "/change_this_path/cgicc.log", std::ios::app );
#endif

using namespace std;
using namespace cgicc;

using namespace cimg_library;

typedef complex<double> dcmpx;


void P4_Tile(CImg<unsigned char> *src){
CImg<unsigned char> result((*src));
	for(int i=0;i<result.width();i++){
	  for(int j=0;j<result.height();j++){
	  	double ci,cj;
	  	
	  	ci=2*abs(i-(result.width()-1)/2.0);
	  	cj=2*abs(j-(result.height()-1)/2.0);
//	  	if(cj>=result.height()) cj-=1;	  		  	
	  	
	  	(*src)(i,j,0) = result(int(ci),int(cj),0);
    	(*src)(i,j,1) = result(int(ci),int(cj),1);
      (*src)(i,j,2) = result(int(ci),int(cj),2);
	  }
	  
	}
}


void PolyImg(Polynomial *P,CImg<unsigned char> src, CImg<unsigned char> *dest,int r,int t){
	dcmpx z,I=dcmpx(0.0,1.0);
	double pi=3.141592653;
	double twist=t;
	double unit=r*src.height()/(2*pi);

	double scale=exp(src.width()/unit);
	dcmpx X1=(2*pi*I + twist*log(scale))/(2*pi*I);
	for(int i=0;i<dest->width();i++){
	  for(int j=0;j<dest->height();j++){
	  	double ci,cj;

	  	cj=(j-dest->height()/2)/unit;
	  	ci=(i-dest->width()/2)/unit;
	  	
	  	z=dcmpx(r)*dcmpx(ci,cj);
	  	z=X1*log(P->eval(z));
	
	  	ci=z.real();
	  	ci=ci*unit+src.width()/2;
	  	ci=int(ci)%src.width();
	  	if(ci<0)ci+=src.width();
	  	
	  	cj=z.imag();
	  	cj=cj*unit+src.height()/2;
	  	cj=int(cj)%src.height();
	  	if(cj<0)cj+=src.height();
	  	
	  	
	  	(*dest)(i,j,0) = src(int(ci),int(cj),0);
    	(*dest)(i,j,1) = src(int(ci),int(cj),1);
      (*dest)(i,j,2) = src(int(ci),int(cj),2);
	  }
 	}	
}


int main(int /*argc*/, char ** /*argv*/)
{
  try {
#if HAVE_GETTIMEOFDAY
    timeval start;
    gettimeofday(&start, NULL);
#endif

    // Create a new Cgicc object containing all the CGI data
    Cgicc cgi;
    
    // Output the HTTP headers for an HTML document, and the HTML 4.0 DTD info
    cout << HTTPHTMLHeader();
    cout << html() << endl;

    // Set up the page's header and title.
    // I will put in lfs to ease reading of the produced HTML. 
    cout << head() << endl;

    // Output the style sheet portion of the header

    cout << title() << "Picture Results"<< title() << endl;

    cout << head() << endl;
    
    // Start the HTML body
    cout << body() << endl;

    cout << h1() << "Your Transformation Results" << h1() << endl;
    
    // Get a pointer to the environment
    const CgiEnvironment& env = cgi.getEnvironment();
    
    
    // Show the uploaded file
    cout << h2("File Uploaded via FormFile") << endl;
  
    const_file_iterator file;
    file = cgi.getFile("ipict");
    
    form_iterator poly,P4,rotations,twist,SaveAs,StudID,ImageSize;//form variables
    
    poly=cgi.getElement("poly");
    P4=cgi.getElement("P4");
    rotations=cgi.getElement("rotations");
    twist=cgi.getElement("twist");
		SaveAs=cgi.getElement("SaveAs");
		StudID=cgi.getElement("StudID");	
		ImageSize=cgi.getElement("ImageSize");	
			
    if(file != cgi.getFiles().end()) {
			cout << cgicc::div() << endl;

			cout << table().set("border","0").set("rules","none").set("frame","void").set("cellspacing","2").set("cellpadding","2") << endl;

		 
			cout << tr() << td("File")<< td((*file).getFilename())  << tr() << endl;
	
			cout << tr() << td("Polynomial")<< td(poly->getValue()) << tr() << endl;
	
			cout << tr() << td("Tiled");

			if(P4!=cgi.getElements().end()){
				cout<<td("Yes");
			}
			else{
				cout<<td("No");
			}
	
			cout<< tr() << endl;
			cout<<tr()<<td("Rotations")<<td(rotations->getValue())<<tr()<<endl;
			cout<<tr()<<td("Twist")<<td(twist->getValue())<<tr()<<endl;
	
			cout << table() << cgicc::div() << endl;
			cout << pre() << td() << tr() << endl;  

			string DirName="/var/www/PnP_Image/",fname,defaultname,ext="jpg",fullname;//file info

			defaultname="Pict_"+ToString(abs(cimg::time()%100));

			//get extension
			fname=(*file).getFilename();
			for(int i=fname.length();i>0;i--){
				if(fname[i]=='.'){
					ext=fname.substr(i+1,fname.length()-i);
					i=0;
				}
	
			}

			if(SaveAs!=cgi.getElements().end()&&StudID->getValue().length()!=0){
				ofstream ofParams((DirName+StudID->getValue()+".htm").c_str());				
				ofParams << "<html>" << endl;			
				ofParams << head() << endl;
				ofParams << title() << StudID->getValue()<< title() << endl;
				ofParams << head() << endl;
				ofParams << "<body>" << endl;
				ofParams<< cgicc::div().set("align","center")<<endl;
				ofParams << table().set("border","0")<< endl;
				ofParams << tr() << td("ID:")<< td(StudID->getValue())  << tr() << endl;
				ofParams << tr() << td("Polynomial:")<< td(poly->getValue()) << tr() << endl;
				ofParams << tr() << td("Tiled:");
				if(P4!=cgi.getElements().end()){
					ofParams<<td("Yes");
				}
				else{
					ofParams<<td("No");
				}
				ofParams<< tr() << endl;
				ofParams<<tr()<<td("Rotations:")<<td(rotations->getValue())<<tr()<<endl;
				ofParams<<tr()<<td("Twists:")<<td(twist->getValue())<<tr()<<endl;
				ofParams << table()  << endl;
		
				ofParams<<h2()<<"Original Image"<<h2()<<endl;
				ofParams<<img().set("src","http://joshicola.no-ip.org/PnP_Image/"+StudID->getValue()+"_o."+ext).set("alt","original")<<"<br>"<<endl;      	
	
				ofParams<<h2()<<"Transformed Image"<<h2()<<endl;
				ofParams<<img().set("src","http://joshicola.no-ip.org/PnP_Image/"+StudID->getValue()+"_t."+ext).set("alt","Transformation")<<"<br>"<<endl;      	
					
				ofParams<< cgicc::div()<<endl;
				ofParams <<"</body>" << endl;
				ofParams <<"</html>" << endl;				
				ofParams.flush();ofParams.close();
				ifstream ifIDList;
				ifIDList.open("/var/www/PnP_Image/Gallery.htm",ifstream::in);
	
				int found=0;
				string str="";
				while(ifIDList.good()&&!found){
					if(str.find(StudID->getValue(),0)!=string::npos) found=-1;
	
					getline(ifIDList,str);
				}
				if(!found){
					ofstream ofIDList;
					ofIDList.open("/var/www/PnP_Image/Gallery.htm",ofstream::out|ofstream::app);
					ofIDList<<a().set("href",StudID->getValue()+".htm")<<
					img().set("src","http://joshicola.no-ip.org/PnP_Image/"+StudID->getValue()+"_th."+ext)<<
					StudID->getValue()<<					
					a()<<br()<<endl;
					ofIDList.flush();ofIDList.close();
				}
	
	
				fname=StudID->getValue()+"_o."+ext;
			}
			else{      
				fname=defaultname+"_o."+ext;
			}


			fullname = DirName + fname;

			ofstream foo(fullname.c_str());
			(*file).writeToStream(foo);
			foo.flush();//Make the file available to manipulate from the disk
			foo.close();
	
	
			//Display the image
			cout<<cgicc::div().set("align","center")<<endl;
	
			string s=poly->getValue();

			Polynomial *P=new Polynomial(s);
			cout<< s<<P->print()<<P->get_error()<<endl;

			if(P->has_error()!=-1){
				double ratio=1;
				//load CImg
				CImg<unsigned char> src(fullname.c_str()),result(src,false);
				int MaxSize=atoi(ImageSize->getValue().c_str()),MinSize=MaxSize*400/1024;
				if(src.width()>MaxSize||src.height()>MaxSize||(src.width()<MinSize&&src.height()<MinSize)){
					int ox=src.width(),oy=src.height();
					if(src.width()>src.height())ratio=(double)MaxSize/src.width();
					else ratio=(double)MaxSize/src.height();
					src.resize(int(src.width()*ratio),int(src.height()*ratio));
					if(ox>=MinSize||oy>=MinSize){
						src.save(fullname.c_str());
					}				
				}
	
				result.resize(MaxSize,MaxSize*3/4);//all results will be 1024X768

				cout<<h2()<<"Your Original Image"<<h2()<<endl;
				cout<<img().set("src","http://joshicola.no-ip.org/PnP_Image/"+fname).set("alt","original")<<endl;
	
				//process Img
				if(P4!=cgi.getElements().end()){ 	
					P4_Tile(&src);
//					cout<<"Yippeee!!! a P4 !!!"<<endl;
//					fullname=DirName+defaultname+"_test."+ext;
//					src.save(fullname.c_str());
		 	 	}

			if(SaveAs!=cgi.getElements().end()&&StudID->getValue().length()!=0){
				fname=StudID->getValue()+"_t."+ext;
			}
			else{      
				fname=defaultname+"_t."+ext;
			}

			fullname = DirName + fname;

			PolyImg(P,src,&result,atoi(rotations->getValue().c_str()),atoi(twist->getValue().c_str()));
			//Save Img
			result.save(fullname.c_str());
	
			if(SaveAs!=cgi.getElements().end()&&StudID->getValue().length()!=0){
				fullname=DirName+StudID->getValue()+"_th."+ext;
				result.resize(75,50);
				result.save(fullname.c_str());
			}
		 }

		cout<<h2()<<"The Transformed Image"<<h2()<<endl;
		cout<<P->print()<<br()<<endl;
		if(P->has_error()){cout<<P->get_error()<<br()<<endl;}
		if(P->has_error()!=-1){
			cout<<img().set("src","http://joshicola.no-ip.org/PnP_Image/"+fname).set("alt","Transformation")<<endl;
		}
		cout<<cgicc::div()<<endl;

	}
	else {
		cout << p() << cgicc::div().set("class", "notice") << endl;
		cout << "No file was uploaded." << endl << cgicc::div() << p() << endl;
	 }

    // Now print out a footer with some fun info
    cout << p() << cgicc::div().set("align","center");
    cout << a("Back to form").set("href", cgi.getEnvironment().getReferrer()) 
	 << endl;
    cout << cgicc::div() << br() << hr() << endl;

    cout << body() << html() << endl;

    // No chance for failure in this example
    return EXIT_SUCCESS;
  }

  // Did any errors occur?
  catch(const std::exception& e) {

    // This is a dummy exception handler, as it doesn't really do
    // anything except print out information.

    // Reset all the HTML elements that might have been used to 
    // their initial state so we get valid output
    html::reset(); 	head::reset(); 		body::reset();
    title::reset(); 	h1::reset(); 		h4::reset();
    comment::reset(); 	td::reset(); 		tr::reset(); 
    table::reset();	cgicc::div::reset(); 	p::reset(); 
    a::reset();		h2::reset(); 		colgroup::reset();

    // Output the HTTP headers for an HTML document, and the HTML 4.0 DTD info
    cout << HTTPHTMLHeader() << HTMLDoctype(HTMLDoctype::eStrict) << endl;
    cout << html().set("lang","en").set("dir","ltr") << endl;

    // Set up the page's header and title.
    // I will put in lfs to ease reading of the produced HTML. 
    cout << head() << endl;

    // Output the style sheet portion of the header
    cout << style() << comment() << endl;
    cout << "body { color: black; background-color: white; }" << endl;
    cout << "hr.half { width: 60%; align: center; }" << endl;
    cout << "span.red, strong.red { color: red; }" << endl;
    cout << "div.notice { border: solid thin; padding: 1em; margin: 1em 0; "
	 << "background: #ddd; }" << endl;

    cout << comment() << style() << endl;

    cout << title("GNU cgicc exception") << endl;
    cout << head() << endl;
    
    cout << body() << endl;
    
    cout << h1() << "GNU cgi" << span("cc", set("class","red"))
	 << " caught an exception" << h1() << endl; 
  
    cout << cgicc::div().set("align","center").set("class","notice") << endl;

    cout << h2(e.what()) << endl;

    // End of document
    cout << cgicc::div() << endl;
    cout << hr().set("class","half") << endl;
    cout << body() << html() << endl;
    
    return EXIT_SUCCESS;
  }
}
